package cs343;

import java.awt.*;
import java.awt.event.KeyEvent;
import javax.swing.JOptionPane;
import javax.swing.JPanel;

/**
* <p>
* Title: CS 343 Project: Pong
* </p>
* <p>
* Description: CS 343 Project  
* This class deals with the arena, paddle and ball graphics.
* It makes calls to methods within the Paddle and Ball 
* classes to check for collision, out of bounds, etc.
* </p>
* 
* @author Jenny Windsperger, Stirling Pankow, Will Prew, Shane O'Malley-Potting
* @email jennifer.windsperger@my.uwrf.edu, stirling.pankow@my.uwrf.edu,
*        william.prew@my.uwrf.edu, shane.omalley-potting@my.uwrf.edu
* @date December 1st 2011
*/
public class Arena extends JPanel implements Runnable {

	private static final long serialVersionUID = 1L;

	//Thread for this class.  It will run itself in the constructor
	Thread thread;
	
	//variables that define various object dimensions
	private int arenaHeight = 400;
	private int arenaWidth = 800;
	//Paddle dimensions
	private int paddleHeight = 50;
	private int paddleWidth = 20;
	//Ball initial values
	private int ballX = 400;
	private int ballY = 200;
	private int ballHeading = 20;
	private int ballSpeed = 10;
	private int ballRadius = 10;
	private int count;
	
	private int paddleIncrement = 10;
	
	//a ball object
	private Ball ball = null;
	//A player paddle and AI paddle
	private Paddle humanPaddle = null;
	private Paddle aiPaddle = null;
	
	//two variables to keep track of player intent
	private boolean upFlag = false;
	private boolean downFlag = false;
	
	//Game loop control variable
	private boolean gameON;
	
	
	/**
	 * Default constructor that declares the two paddles, the ball and starts the threads
	 */
	public Arena(){
		{
			int x = (int)Math.round(Math.random() * 30 + 15);
			int y = (int)Math.round(Math.random());
			if(y == 1)
				this.ballHeading = x;
			else
				this.ballHeading = 360 - x;
		}
		count = 0;
		humanPaddle = new Paddle(paddleWidth, paddleHeight, arenaHeight/2 - paddleHeight/2 );
		aiPaddle = new Paddle(paddleWidth, paddleHeight, arenaHeight/2 - paddleHeight/2);
		ball = new Ball(ballX, ballY, ballSpeed, ballRadius, ballHeading );
		gameON = true;
		thread = new Thread(this);
		thread.start();
	}
	/**
	 * Method resets the arena to it's initial values
	 * Postcondition: the arena is just like new
	 */
	public void reset(){
		{
			int x = (int)Math.round(Math.random() * 30 + 15);
			int y = (int)Math.round(Math.random());
			if(y == 1)
				this.ballHeading = x;
			else
				this.ballHeading = 360 - x;
		}
		humanPaddle = new Paddle(paddleWidth, paddleHeight, arenaHeight/2 - paddleHeight/2 );
		aiPaddle = new Paddle(paddleWidth, paddleHeight, arenaHeight/2 - paddleHeight/2);
		ball = new Ball(ballX, ballY, ballSpeed, ballRadius, ballHeading );
		gameON = true;
		thread = new Thread(this);
		thread.start();
	}
	
	/**
	 * Method that calls various methods to control the game such as checkForCollision,
	 * moveAhead and repaint
	 * Precondition: Arena is created
	 * Postcondition: Game is over because ball went out of bounds
	 */
	public void run() {	
		while(gameON){
			repaint();
			
			//Move the ball
			ball.moveAhead(ballSpeed);
		
			//ReDraw the ball
			repaint();
			
			//add a delay here 
			try {
				Thread.sleep(60);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
			
			//Move the Paddles
			moveHumanPaddle();
			moveAIPaddle();
			
			//Redraw the Paddles
			repaint();

			//Check for ball collision
			if( ball.getHeading() > 270 || ball.getHeading() < 90){
				ball.checkCollision(arenaHeight, arenaWidth, humanPaddle);
			}
			if( ball.getHeading() > 90 && ball.getHeading() < 270){
				ball.checkCollision(arenaHeight, arenaWidth, aiPaddle);
			}
			//Check if ball went out of bounds
			gameON = ball.outOfBounds(arenaWidth);
			
			if(ball.isCollision()){
				ballSpeed += 2;
				ball.setSpeed(ballSpeed);
			}
		}
		
		//ask for alias because game is over
		HighScores highScore = new HighScores();
		
		try {
			if(highScore.checkScore(ball.getHeading())){
				String alias = JOptionPane.showInputDialog(null, "Your score is " + ball.getScore() + "\nEnter 3 letter alias for the scoreboard: ");
				//make sure they only enter in three letters
				while(alias.length() != 3){
					alias = JOptionPane.showInputDialog(null, "Enter 3 letter alias for the scoreboard: ");
				}
			
				highScore.updateScores(new Score(ball.getScore(), alias));
			}
			else{
				JOptionPane.showInternalMessageDialog(null, "You scored " + ball.getScore() + "! Not a high score though, maybe next time.");
			}
		} catch (Exception e) {
			
		}
		if(JOptionPane.showConfirmDialog(null, "Would you like to play again?") == JOptionPane.YES_OPTION)
			reset();
		else
		//exit when the game is over
		System.exit(0);
	}
	
	/**
	 * Main paintComponent method for panel
	 * Postcondition: Ball and paddles are painted to the arena
	 */
	public void paintComponent(Graphics g){
		setOpaque(false);
		super.paintComponent(g);
		
		//ball will be red
		g.setColor(Color.red);
		
		//ball
		g.fillOval(ball.getxPosition()-ball.getRadius(), ball.getyPosition() - ball.getRadius(), ball.getRadius() * 2, ball.getRadius() * 2);
		
		//paddles will be black
		g.setColor(Color.black);
		
		//player paddle
		g.fillRect(arenaWidth - humanPaddle.getPaddleWidth(), humanPaddle.getPaddlePosition() - humanPaddle.getPaddleHeight()/2, humanPaddle.getPaddleWidth(), humanPaddle.getPaddleHeight() );
		
		//ai paddle
		g.fillRect(0, aiPaddle.getPaddlePosition() - aiPaddle.getPaddleHeight()/2, aiPaddle.getPaddleWidth(), aiPaddle.getPaddleHeight());
	}
	
	
	/**
	 * Method to move player Paddle
	 * The flags are updated by key events
	 * Precondition: up arrow or down arrow are pressed
	 * Postcondtion: paddle is move to reflect the key pressed
	 */
	public void moveHumanPaddle(){
		if(upFlag == true){
			humanPaddle.move(-paddleIncrement);
		}else if(downFlag == true){
			humanPaddle.move(paddleIncrement);
		}
	}
	
	/**
	 * Method to move the computer paddle
	 * simple AI of moving toward ball y position
	 * Postcondition: AI paddle will move with the ball
	 */
	public void moveAIPaddle(){
		
		if(aiPaddle.getPaddlePosition()  > ball.getyPosition()){
			aiPaddle.move(-paddleIncrement);
		}
		if(aiPaddle.getPaddlePosition() < arenaHeight - paddleHeight){
			if(aiPaddle.getPaddlePosition()  < ball.getyPosition()){
				aiPaddle.move(paddleIncrement);
			}
		}
	}
	
	/**
	 * Simple method to check which key is pressed
	 * Postcondition: paddles will move
	 */
	public void pressedKey(KeyEvent e){
		if(e.getKeyCode() == KeyEvent.VK_UP){
			upFlag = true;
			moveHumanPaddle();
			
		}
		if(e.getKeyCode() == KeyEvent.VK_DOWN){
			downFlag = true;
			moveAIPaddle();
		}
	}
	
	/**
	 * Method to deal with released keys
	 * Precondition: a key was pressed
	 * Postcondtion: paddles will no longer move until a key is pressed again
	 */
	public void releasedKey(KeyEvent e){
		if(e.getKeyCode() == KeyEvent.VK_UP){
			upFlag = false;
		}
		if(e.getKeyCode() == KeyEvent.VK_DOWN){
			downFlag = false;
		}
	}
}
